package pkmn.move;

import java.io.File;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import pkmn.type.Type;
import pkmn.util.Util;

public class Move{
    private String name;
    private Type type;
    private int accuracy;
    private int pp;
    private int priority;
    private int maxPP;
    private IndirectAction indirectAction;
    private int indirectAccuracy;
    private int power;
    private boolean special;
    private int multiplicy;
    private boolean self;
    private int criticalLevel;

    /**
     * Constructor.
     */
    @SuppressWarnings(value = "unchecked")
    public Move(String move) throws Exception{
        File xmlfile = new File("src/xml/moves.xml");
	Document d = new SAXBuilder().build(xmlfile);
	Element root = d.getRootElement();
	List<Element> listMoves = root.getChildren();
        for (Element e : listMoves){
            String moveName = e.getAttributeValue("name");
            if (moveName.equals(move)){
                this.name = moveName;
                this.type = Type.newByName(e.getChildText("type"));
                this.pp = Integer.parseInt(e.getChildText("pp"));
                this.maxPP = this.pp;
                this.priority = Integer.parseInt(Util.nvl(e.getChildText("priority"), "0"));
                this.criticalLevel = Integer.parseInt(Util.nvl(e.getChildText("critical"), "0"));
                Element direct = e.getChild("direct");
                if (direct != null){
                    this.power = Integer.parseInt(direct.getChildText("power"));
                    this.accuracy = Integer.parseInt(direct.getChildText("accuracy"));
                    this.special = Boolean.parseBoolean(direct.getChildText("special"));
                    this.multiplicy = Integer.parseInt(Util.nvl (direct.getChildText("multiple"), "1"));
                }
                Element indirect = e.getChild("indirect");
                if (indirect != null){
                    this.indirectAction = IndirectAction.newByName(indirect.getChildText("action"));
                    this.indirectAccuracy = Integer.parseInt(indirect.getChildText("accuracy"));
                    this.self = Boolean.parseBoolean(Util.nvl(indirect.getChildText("self"), "false"));
                }
                break;
            }
        }
    }

    /**
     * Get the name.
     * @return String
     */
    public String getName(){
        return this.name;
    }

    /**
     * Get the type
     * @return Type.
     */
    public Type getType(){
        return this.type;
    }

    /**
     * Get the accuracy.
     * @return int
     */
    public int getAccuracy(){
        return this.accuracy == 0 ? this.indirectAccuracy : this.accuracy;
    }

    /**
     * Get the PP of move.
     * @return int.
     */
    public int getPP(){
        return this.pp;
    }

    /**
     * Get the priority of move.
     * @return int.
     */
    public int getPriority(){
        return this.priority;
    }

    /**
     * Get the critical level of move.
     * @return int.
     */
    public int getCriticalLevel(){
        return this.criticalLevel;
    }

    /**
     * Get the max PP of move.
     * @return int.
     */
    public int getMaxPP(){
        return this.maxPP;
    }

    /**
     * Decrement PP.
     */
    public void decPP(){
        if (this.pp > 0)
            this.pp--;
    }

    /**
     * Restore PP.
     * @param pp The amount of PP to restore.
     */
    public void restore(int pp){
        this.pp = Util.min (this.pp += pp, this.maxPP);
    }

    /**
     * Restore PP to max.
     */
    public void restore(){
        this.pp = this.maxPP;
    }

    /**
     * Comparison between two moves.
     * @param move is the move to compare.
     * @return boolean
     */
    public boolean equals(Move move){
        return this.name.equals(move.getName());
    }

    /**
     * Test if this move have multiple hits.
     * @return boolean
     */
    public int getMultiplicy(){
        return this.multiplicy;
    }

    /**
     * Test if this move is special.
     * @return boolean
     */
    public boolean isSpecial(){
        return this.special;
    }

    /**
     * Get the PP of move.
     * @return int
     */
    public int getPower(){
        return this.power;
    }

    /**
     * Get the effect of move.
     * @return IndirectAction
     */
    public IndirectAction getIndirectAction(){
        return this.indirectAction;
    }

    /**
     * Get the effect of move.
     * @return IndirectAction
     */
    public int getIndirectAccuracy(){
        return this.indirectAccuracy;
    }

    public boolean isDirect(){
        return (this.power != 0);
    }

    public boolean isSelf(){
        return this.self;
    }

    public static void shift(Move[] moves){
        while (moves[0] == null){
            moves[0] = moves[1];
            moves[1] = moves[2];
            moves[2] = moves[3];
            moves[3] = null;
        }
    }
    
    @Override
    public String toString(){
        return this.name;
    }
}